package edu.cicese.tm;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.nio.channels.FileChannel;

/**
 * Created by: Eduardo Quintana Contreras
 * Date: 28/02/11
 * Time: 02:31 PM
 */
public class Utilities {

//	public static String appDir = "C:\\ANScapturas\\";
	public static String appDir = "D:\\Tests\\Experimento9991.1\\";
//	public static String appDir = "D:\\Pasitos\\ans-tm\\";
	public static String spaceDir = appDir + "spaces\\";
	public static String tagSize = "all";

	public final static int CREATED = 301;
	public final static int DELETED = 302;
	public final static int MODIFIED = 303;
	public final static int NO_ACTION = 304;

	public static String[][] imgResolutions = {
			{ "100x75", "100", "75" },
//			{ "320x240", "320", "240" },
			{ "480x360", "480", "360" },
//			{ "640x480", "640", "480" },
			{ "800x600", "800", "600" }
	};
	public static String[] poiResolutions = { "320x240", "480x360", "640x480", "800x600" };
	public static String[] thresholds = { "0001", "0002", "0005", "001" };
	public static float[] thresholdsf = { 0.0001f, 0.0002f, 0.0005f, 0.001f };
	public static String[] tagSizes = { "300", "450", "660", "all", "matched" };
	
	public static final int SINGLE_SELECTION = 801;
	public static final int NO_SELECTION = 802;
	public static final int MULTIPLE_SELECTION = 803;
	public static final int SELECTING_AREA = 804;

	//! Adds zeros (to the left)
	public static String addZeros(int index, int length) {
		String indexWithZeros = String.valueOf(index);
		while (indexWithZeros.length() < length) {
			indexWithZeros = "0" + indexWithZeros;
		}
		return indexWithZeros;
	}

	//! Returns a file name without extension
    public static String filenameWithoutExtension(String name) {
	    int dot = name.lastIndexOf(".");
	    int sep = name.lastIndexOf(File.separator);
	    return name.substring(sep + 1, dot);
  	}

	//! Loads the changelog
	public static JSONArray loadJSONArray(String filename) {
		String changelog = loadString(filename);
		if (changelog == null) {
			saveString(filename, new JSONArray().toJSONString());
			return new JSONArray();
		}
		return (JSONArray) JSONValue.parse(changelog);
	}

	//! Loads the changelog
	public static JSONObject loadJSONObject(String filename) {
		String changelog = loadString(filename);
		if (changelog == null) {
			saveString(filename, new JSONObject().toJSONString());
			return new JSONObject();
		}
		return (JSONObject) JSONValue.parse(changelog);
	}

	//! Loads a String from a file
	public static String loadString(String filename) {
		String string = "";
//		boolean separatorAdded = false;
		try {
			//use buffering, reading one line at a time
			//FileReader always assumes default encoding is OK!
			BufferedReader br =  new BufferedReader(new FileReader(new File(filename)));
			try {
				String line = br.readLine();
				while (line != null){
					string += line;
					line = br.readLine();
					if (line != null) {
						string += System.getProperty("line.separator");
					}
//					separatorAdded = true;
				}
//				String line;
//				while ((line = br.readLine()) != null){
//					string += line;
//					string += System.getProperty("line.separator");
//					separatorAdded = true;
//				}
//				if (separatorAdded) {
//					string = string.substring(0, string.length() - 2);
////					System.out.println("<" + System.getProperty("line.separator") + ">");
//				}
			}
			finally {
				br.close();
			}
		}
		catch (IOException e){
//			System.out.println("File missing.");
//			e.printStackTrace();
			return null;
		}

		return string;
//
//		try {
//			BufferedReader br = new BufferedReader(new FileReader(new File(filename)));
//			String string = br.readLine();
//			br.close();
//			return string;
//		} catch(IOException e) {
//			System.out.println("File missing.");
//  			e.printStackTrace();
//  			return null;
//  		}
	}

	//! Saves an object to a file
	public static void saveToFile(Object object, String filename) {
		try {
			ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(new File(filename)));
			stream.writeObject(object);
			stream.close();
		}
		catch (IOException e) { e.printStackTrace(); }
	}

	//! Saves a String to a file
	public static void saveString(String filename, String string) {
		try {
			PrintWriter pw = new PrintWriter(filename);
			pw.print(string);
			pw.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}

	//! Adds a 'tag/interest-point creation/deletion' entry to the changelog
	@SuppressWarnings({"unchecked"})
	public static void addToLog(String spaceID, String ID, String logFile) {
		JSONObject joEntries = loadJSONObject(spaceDir + logFile);
		joEntries.put(spaceID + ID, MODIFIED);
		saveString(spaceDir + logFile, joEntries.toJSONString());
	}

	//! Adds an 'interest-point deletion' entry, for every .poi file in the space, to the changelog
	public static void addToLog(String spaceID) {
		File dir = new File(getPoiDir(spaceID));
		FilenameFilter filter = new FilenameFilter() {
		      public boolean accept(File dir, String name) {
		          return name.toLowerCase().endsWith(".poi");
		      }
		};
		File[] files = dir.listFiles(filter);
		for (File f : files) {
			addToLog(spaceID, f.getName().substring(0, 3), "POIchangelog.ans");
		}
	}

	//! Adds a 'interest-point creation/deletion' entry to the changelog
//	@SuppressWarnings({"unchecked"})
//	private void addPOILog(String poiID) {
//		JSONObject joPOIs = loadJSONObject(Utilities.spaceDir + "POIchangelog.ans");
//		joPOIs.put(frmSpace.spaceID + poiID, Utilities.MODIFIED);
//		Utilities.saveString(Utilities.spaceDir + "POIchangelog.ans", joPOIs.toJSONString());
//	}

	public static String getImgDir(String spaceID) {
		return spaceDir + spaceID + "\\imgs\\";
	}

	public static String getTagDir(String spaceID) {
		return spaceDir + spaceID + "\\tags\\";
	}

	public static String getPoiDir(String spaceID) {
		return spaceDir + spaceID + "\\pois\\800x600\\0001\\";
	}

	public static String getPoiDir(String spaceID, String resolution, String threshold) {
		return spaceDir + spaceID + "\\pois\\" + resolution + "\\" + threshold + "\\";
	}

	public static String getPoiBaseDir(String spaceID) {
		return spaceDir + spaceID + "\\pois\\";
	}
	
	//! Deletes a directory and all its content
	@SuppressWarnings({"ResultOfMethodCallIgnored"})
	public static void deleteDirectory(String path) {
		try {
			System.out.println("Deleting " + path);
			File dir = new File(path);
			File[] files = dir.listFiles();
			if (files != null) {
				for (File file : files) {
					if (file.isDirectory()) {
						deleteDirectory(file.getCanonicalPath());
					}
					if (!file.delete()) {
						System.out.println("Couldn't delete " + file);
					}
				}
			}
			if (!dir.delete()) {
				System.out.println("Couldn't delete " + dir);
			}
		}
		catch (IOException e) { e.printStackTrace(); }
		catch (NullPointerException e) { e.printStackTrace(); }
	}

//	//! Deletes a file
//	public static void deleteFile(String path) {
//		try {
//			System.out.println("Deleting " + path);
//			File dir = new File(path);
//			File[] files = dir.listFiles();
//			for (File file : files) {
//				if (file.isDirectory()) {
//					deleteDirectory(file.getCanonicalPath());
//				}
//				file.delete();
//			}
//			dir.delete();
//		}
//		catch (IOException e) { e.printStackTrace(); }
//		catch (NullPointerException e) { e.printStackTrace(); }
//	}

	//! Copies the recorded audio to a file inside the tag directory
	public static void saveAudioClip(String filename) {
		File tmpAudioFile = new File(spaceDir + "tmpAudio.wav");
		File newAudioFile = new File(filename);

		if (tmpAudioFile.exists()) {
			try {
				FileInputStream in = new FileInputStream(tmpAudioFile);
				FileOutputStream out = new FileOutputStream(newAudioFile);

				byte[] buffer = new byte[4096];
				int bytesRead;
				while ((bytesRead = in.read(buffer)) > 0){
					out.write(buffer, 0, bytesRead);
				}
				in.close();
				out.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}

			System.out.println("Audio file copied. (" + filename + ")");
		}
		else {
			System.out.println("Temporal audio file missing.");
		}
	}
	
	//! Copies the recorded audio to a file inside the tag directory
	public static void copyFile(String currentFilename, String newFilename) {
		File currentFile = new File(currentFilename);
		File newFile = new File(newFilename);

		if (currentFile.exists()) {
			try {
				FileInputStream in = new FileInputStream(currentFile);
				FileOutputStream out = new FileOutputStream(newFile);

				byte[] buffer = new byte[4096];
				int bytesRead;
				while ((bytesRead = in.read(buffer)) > 0){
					out.write(buffer, 0, bytesRead);
				}
				in.close();
				out.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}

			System.out.println("File copied. (" + newFilename + ")");
		}
		else {
			System.out.println("File missing.");
		}
	}

	//! Checks working directories
	public static void checkDirs() {
		new File(spaceDir).mkdirs();
		new File(appDir + "\\plan").mkdir();
	}

	public static void copyFile(File sourceFile, File destFile) throws IOException {
		if (!destFile.exists()) {
			destFile.createNewFile();
		}
		FileInputStream fIn = null;
		FileOutputStream fOut = null;
		FileChannel source = null;
		FileChannel destination = null;
		try {
			fIn = new FileInputStream(sourceFile);
			source = fIn.getChannel();
			fOut = new FileOutputStream(destFile);
			destination = fOut.getChannel();
			long transfered = 0;
			long bytes = source.size();
			while (transfered < bytes) {
				transfered += destination.transferFrom(source, 0, source.size());
				destination.position(transfered);
			}
		} finally {
			if (source != null) {
				source.close();
			} else if (fIn != null) {
				fIn.close();
			}
			if (destination != null) {
				destination.close();
			} else if (fOut != null) {
				fOut.close();
			}
		}
	}


	@SuppressWarnings("unchecked")
	public static void createChangeLog() {
		//Utilities.loadJSONArray(Utilities.spaceDir + "changelog.ans");
		JSONArray jaChangelog = new JSONArray();
		JSONObject joSpace;
		JSONArray jaTags;
		JSONObject joTag;
		File spaceDirectory = new File(spaceDir);
		FileFilter filter = new FileFilter() {
      		public boolean accept(File file) {
          		return file.isDirectory();
      		}
		};
		File[] spaces = spaceDirectory.listFiles(filter);
		File tagDir;
		File[] tags;
		if (spaces != null) {
			for (File space : spaces) {
				tagDir = new File(getTagDir(space.getName()) + tagSize);
				tags = tagDir.listFiles(filter);
				joSpace = new JSONObject();
				joSpace.put("spaceID", space.getName());
				joSpace.put("action", CREATED);
				jaTags = new JSONArray();
				if (tags != null) {
					for (File tag : tags) {
						joTag = new JSONObject();
						joTag.put("tagID", tag.getName());
						joTag.put("action", CREATED);
						jaTags.add(joTag);
					}
				}
				joSpace.put("tags", jaTags);
				jaChangelog.add(joSpace);
			}
		}

		try {
			PrintWriter pw = new PrintWriter(spaceDir + "changelog.ans");
			pw.print(jaChangelog.toJSONString());
			pw.close();
		}
		catch (Exception e) { e.printStackTrace();	}
	}
}
